package executors

import org.hibernate.{Session, SessionFactory}
import org.hibernate.cfg.Configuration
import db.File
import db.FileManager
import db.Folder
import db.FolderManager
import db.User
import db.Client
import client_updater.ClientsUpdater
import client_updater.Update
import java.util.Arrays.ArrayList
import scala.collection.mutable.LinkedList
import objects._
import client_updater.FileUpdate
import scala.actors.Actor

/**
 * Processes an update about a file that was added to a client's dropbox.<br>
 * communicates with the database and sends updates for other clients.
 */
class NewFileExecutor extends Actor{

  /**
   * the acting method of the actor
   */
  def act(){
    loop{
      react{
        case (receivedFile : File2)=> 
          sender ! execute(receivedFile)
        case "Quit" => exit()
        case _ => println("NewFileExecutor received unknown message")
      }
    }
  }
  
  /**
   * receives a File2 that contains details about a file that was added to a client's dropbox.<br>
   * communicates with the database and the disk, and sends updates for other clients.<br>
   * @param - receivedFile : File2, details about the new file<br>
   * @returns - true if the new file already exists in the database and false if it's need to be uploaded.
   */
  private def execute(receivedFile: File2): Boolean = {
    val cfg = new Configuration()
    var sessionFactory = null.asInstanceOf[SessionFactory]
    var session = null.asInstanceOf[Session]
    try{
    sessionFactory = cfg.configure().buildSessionFactory()
    session = sessionFactory.openSession()
    //get files with the given id from database
    var query = session.createQuery("from File f where f.fileID = " + receivedFile.code +
    								" and f.size = " + receivedFile.size)
    val fileInstances = query.list()
    if (fileInstances.isEmpty()) {
      return false
    }
    
    query = session.createQuery("from Folder f where f.folderID = " + receivedFile.parent)
    //get the folder from the database in order to know who the users are
    val folderUsers = query.list().toArray
    val fileManager = new FileManager(session)

    //saves the file in the database
    var file = new File
    file.setFileID(receivedFile.code)
    file.setFileName(receivedFile.name)
    file.setSize(receivedFile.size)
    file.setParentFolder(receivedFile.parent)
    fileManager.saveFile(file)

    var clients = new LinkedList[Client]
    //collects all relevant clients
    for( f <- folderUsers ){
      query = session.createQuery("from Client c where c.userID = " + f.asInstanceOf[Folder].getUserID)
      var newClients = query.list().toArray
      for(c <- newClients ){
        clients = clients :+ c.asInstanceOf[Client]
      }
    }
    //adds an update for each client
    for( c <- clients ){
      if(c.asInstanceOf[Client].getClientID != receivedFile.cid)
      ClientsUpdater.addUpdate(c.asInstanceOf[Long], new FileUpdate("newFile", receivedFile.name, 
    		  										receivedFile.parent, file.getFileID))
    }
    /*folderUsers.foreach(folder => {
      query = session.createQuery("from Clients where user_ID = '" + folder.getUserID + "'")
      var newClients = query.list().asInstanceOf[List[Client]]
      clients.addAll(newClients)
    })*/
    //adds an update for each client
    /*clients.foreach(c => {
      if (c != client) {
        var update = new FileUpdate("NewFile", file.getName, file.getParent, null) //!!!!!!!!!!!!!!
        ClientsUpdater.addUpdate(update, c)
      }
    })*/
    session.flush
    } catch { case (e : Exception) => println(e.printStackTrace) }
    return true
  }
  
}